/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#include "nodehandler.h"

#include "atc.h"

#include "aircraft_data.h"
#include "canvas_action.h"
#include "canvas_types.h"
#include "engine.h"
#include "param.h"
#include "param_impl.h"

#include "display_task.h"
#include "feedback_task.h"
#include "inputtask.h"
#include "instructiontask.h"
#include "task.h"
#include "trialtask.h"
#include "taskwidget.h"
#include "uicomponentbuilder.h"

#include "document.h"
#include "presenter.h"
#include "conflictdeclaration.h"
#include "param.h"

#include <qapplication.h>	// allWidgets()
#include <q3frame.h>
#include <q3hbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qvalidator.h> 
#include <qvariant.h> 
//#include <qwidcoll.h>		// widget list classes

#include <iostream>

#ifdef _WIN32
	#include <assert.h>
#endif

using namespace pact;


////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Input Screen Node Handler
//
//--------------------------------------------------------------------------------------------------
//
//

/*!
 */
void InputNodeHandler::operator ()( const xml::DocumentNode* node ) {
	InputTask *task = dynamic_cast<InputTask*>( _view );

	if ( "font" == node->type ) {
		task->setFont( QFont( 
				_doc->getAttributeValue( node, "family" ).c_str(),
				_doc->getIntegerAttribute( node, "pointSize" ),
				_doc->getIntegerAttribute( node, "weight" ),
				_doc->getBooleanAttribute( node, "italic" )
			) );
	}

	else if ( "ui_component" == node->type ) {
		task->addWidget( UIComponentBuilder::build(
				_doc,
				_doc->getReferencedNode( _doc->getAttributeValue( node, "ref" ) ),
				task
			) );
	}

	else if ( "connection" == node->type ) {
        UIConnectionNodeHandler tmp(_doc, _view);
        _doc->process_children(node, tmp);
	} 
	
	else {
		throw nodehandler_error(
				"illegal input screen node entry <" + node->type + ">"
			);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Display Screen Node Handler
//
//--------------------------------------------------------------------------------------------------
//
//

/*!
 *
 */
void DisplayNodeHandler::operator ()( const xml::DocumentNode *node ) {
	DisplayTaskBuilder *builder = dynamic_cast<DisplayTaskBuilder*>( _view );

	if ( "text" == node->type ) {
		builder->set_text( _doc->getStringContent(node) );
	}
	else if ( "link" == node->type ) {
		builder->set_link( _doc->getAttributeValue( node, "global" ) );
	}
	else if ( "countdown" == node->type ) {
		builder->set_countdown( _doc->getIntegerAttribute( node, "time" ) );
	}
	else {
		throw nodehandler_error(
				"illegal display screen node entry <" + node->type + ">"
			);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Feedback Node Handler
//
//--------------------------------------------------------------------------------------------------
//
//

/*!
 *
 */
void 
FeedbackNodeHandler::operator()(const xml::DocumentNode* a_node) 
{
	FeedbackTaskBuilder *builder = dynamic_cast<FeedbackTaskBuilder*>(_view);

	std::map<std::string, std::string> attributes = a_node->parent->attributes;
	std::map<std::string, std::string>::iterator it = attributes.find("type");
		
	if (it != attributes.end())
	{
		if ((*it).second == "selfReferent")
		{
			builder->SetType(FEEDBACK_SELF_REFERENT);
		}
		else if ((*it).second == "normative")
		{
			builder->SetType(FEEDBACK_NORMATIVE);
		}
		else
		{
			builder->SetType(FEEDBACK_GENERAL);
		}
	}

	if (a_node->type == "text") 
	{
		builder->SetText(_doc->getStringContent(a_node));
	}
	else if (a_node->type == "goal")
	{
        FeedbackGoalNodeHandler tmp(_doc, _view);
        _doc->process_children(a_node, tmp);
	}

	else if (a_node->type == "feedback") 
	{
		builder->SetFeedback();
	}
	else if (a_node->type == "conditionalText") 
	{
		std::string condition = _doc->getAttributeValue(a_node, "condition");
		int value = atoi(_doc->getAttributeValue(a_node, "value").c_str());
		std::string text = _doc->getStringContent(a_node);
		builder->SetCondition(condition, value, text);
	}
	else if (a_node->type == "global_ref")
	{
		builder->SetGlobalRef(_doc->getStringContent(a_node));
	}
	else if (a_node->type == "font")
	{
		builder->SetFont(QFont(	_doc->getAttributeValue(a_node, "family").c_str(),
								_doc->getIntegerAttribute(a_node, "pointSize"),
								_doc->getIntegerAttribute(a_node, "weight"),
								_doc->getBooleanAttribute(a_node, "italic")));
	}
	else 
	{
		throw nodehandler_error("illegal feedbacxk screen node entry <" + a_node->type + ">");
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Instruction Node Handler
//
//--------------------------------------------------------------------------------------------------
//
//

/*!
 *
 */
void InstructionNodeHandler::operator ()( const xml::DocumentNode* node ) {
	InstructionTask* task = dynamic_cast<InstructionTask*>(_view);

	if ( "font" == node->type ) {
		task->setFont( QFont( 
				_doc->getAttributeValue( node, "family" ).c_str(),
				_doc->getIntegerAttribute( node, "pointSize" ),
				_doc->getIntegerAttribute( node, "weight" ),
				_doc->getBooleanAttribute( node, "italic" )
			) );
	}

	else if("text" == node->type){
		task->setText(node->content);

	}else if("keyEvent" == node->type){
		task->addTerminationKey( node->content.c_str() );

	}else{
		throw nodehandler_error(
			"illegal instruction node entry <" + node->type + ">"
		);
	}
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
// pact::ParamNodeHandler : xml::NodeHandler
//
//--------------------------------------------------------------------------------------------------

/*!
 */
void ParamNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	if("update_rate" == node->type){
		param.set_update_rate(_doc->getIntegerContent(node));
	}
	else if ("aircraft_acceptance" == node->type)
	{
		std::string strAcceptanceType = _doc->getStringContent(node);
		atc::AircraftAcceptanceType acceptanceType = atc::ACCEPTANCE_MANUAL;
	
		if (strAcceptanceType == "automatic")
		{
			acceptanceType = atc::ACCEPTANCE_AUTOMATIC;
		}

		param.SetAircraftAcceptanceType(acceptanceType);
	}
	else if ("conflictDeclarationActions" == node->type)
	{
		if (_doc->attributeExists(node, "level_change"))
		{
			param.SetConflictDeclarationLevelChange(_doc->getBooleanAttribute(node, "level_change"));
		}

		if (_doc->attributeExists(node, "speed_change"))
		{
			param.SetConflictDeclarationSpeedChange(_doc->getBooleanAttribute(node, "speed_change"));
		}

		if (_doc->attributeExists(node, "audio_feedback"))
		{
			param.SetConflictDeclarationAudioEnabled(_doc->getBooleanAttribute(node, "audio_feedback"));
		}

		if (_doc->attributeExists(node, "score_change"))
		{
			param.SetConflictDeclarationScoreEnabled(_doc->getBooleanAttribute(node, "score_change"));
		}
	}
	else if ( "scenario_tester" == node->type ) {
		param.set_update_multiplier( _doc->getFloatContent(node) );
	}
	else if("counter_format" == node->type){
		param.set_counter_format(_doc->getStringContent(node).c_str());
	}

	else if ( "horizontal_doms" == node->type ) {
		param.set_hdoms( _doc->getDecimalContent(node) );
	}

	else if ( "vertical_doms" == node->type ) {
		param.set_vdoms( _doc->getDecimalContent(node) );
	}

	else if ( "colours" == node->type ) {
        ColourNodeHandler tmp(_doc, _view);
        _doc->process_children( node, tmp);
	}
	else if ( "info_block" == node->type ) {
		std::string pos = _doc->getAttributeValue( node, "position" );
		param.add_info_block(
				"TOPLEFT"     == pos ?		atc::TOPLEFT		:
				"TOP"         == pos ?		atc::TOP    		:
				"TOPRIGHT"    == pos ?		atc::TOPRIGHT		:
				"LEFT"        == pos ?		atc::LEFT			:
				"CENTER"      == pos ?		atc::CENTER  		:
				"RIGHT"       == pos ?		atc::RIGHT			:
				"BOTTOMLEFT"  == pos ?		atc::BOTTOMLEFT		:
				"BOTTOMRIGHT" == pos ?		atc::BOTTOMRIGHT	:
											atc::BOTTOM		
            );
        InfoBlockNodeHandler tmp(_doc, _view);
        _doc->process_children( node, tmp );
	}
	else if ( "select_tools" == node->type ) { 
        ToolsNodeHandler tmp(_doc, _view);
        _doc->process_children( node, tmp );
	}
	else if ( "keyed_tools" == node->type ) {
        KeysNodeHandler tmp(_doc, _view);
        _doc->process_children( node, tmp );
	}
	else if ( "initial_tools" == node->type ) {
        InitialToolsNodeHandler tmp( _doc, _view );
        _doc->process_children( node, tmp);
	}
	else if ( "scoring" == node->type ) {
        ScoringNodeHandler tmp( _doc, _view );
        _doc->process_children( node, tmp );
	}
	else
	{
		throw nodehandler_error( "illegal param node entry <" + node->type + ">" );
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::ColourNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void ColourNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	QColor colour = QColor( _doc->getStringContent(node).c_str() );
	std::string sflash = _doc->getAttributeValue( node, "blink" );
	bool flash = ( "true" == sflash || "1" == sflash );

	if     ( "conflict_colour"    == node->type ) param.set_conflict_colour( colour, flash );
	else if( "cs_none_colour"	  == node->type ) param.set_cs_colour( atc::CS_NONE, colour, flash );
	else if( "cs_annonced_colour" == node->type ) param.set_cs_colour( atc::CS_ANNOUNCED, colour, flash );
	else if( "cs_proposed_colour" == node->type ) param.set_cs_colour( atc::CS_PROPOSED, colour, flash );
	else if( "cs_accepted_colour" == node->type ) param.set_cs_colour( atc::CS_ACCEPTED, colour, flash );
	else if( "cs_overout_colour"  == node->type ) param.set_cs_colour( atc::CS_OVEROUT, colour, flash );
	else if( "cs_handoff_colour"  == node->type ) param.set_cs_colour( atc::CS_HANDOFF, colour, flash );
	else if( "cs_nomore_colour"   == node->type ) param.set_cs_colour( atc::CS_NOMORE, colour, flash );
	else
			throw nodehandler_error( "illegal param node entry <" + node->type + ">" );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::FeedbackGoalNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void 
FeedbackGoalNodeHandler::operator()(const xml::DocumentNode* a_node) 
{
	FeedbackTaskBuilder* builder = dynamic_cast<FeedbackTaskBuilder*>(_view);

	if (a_node->type == "text") 
	{
		builder->SetGoalText(_doc->getStringContent(a_node));
	}
	else if(a_node->type == "link")
	{
		if (_doc->attributeExists(a_node, "global"))
		{
			builder->SetLink(_doc->getAttributeValue(a_node, "global"));
		}
	}
	else
	{
		throw nodehandler_error( "illegal param node entry <" + a_node->type + ">" );
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::InfoBlockNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void InfoBlockNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	if ( "time"  == node->type )	
	{
		param.add_time_info();
	}
	else if ( "goal"  == node->type )	
	{
		atc::INFO_BLOCKS type = atc::GOAL_INFO;
		
		std::map<std::string, std::string> attributes = node->attributes;
		std::map<std::string, std::string>::iterator it = attributes.find("type");
		
		if (it != attributes.end())
		{
			if ((*it).second == "selfReferentGoal")
			{
				type = atc::SR_GOAL_INFO;	
			}
			else if ((*it).second == "normativeGoal")
			{
				type = atc::NORM_GOAL_INFO;
			}
		}

		switch (type)
		{
		case atc::SR_GOAL_INFO:
			param.AddSelfReferentGoalInfo();
			break;
			
		case atc::NORM_GOAL_INFO:
			param.AddNormativeGoalInfo();
			break;

		case atc::GOAL_INFO:
		default:
			param.add_goal_info();

			atc::InfoDisplayDetails details;

			for (xml::DocNodes::const_iterator child = node->children.begin();
					child != node->children.end(); 
					++child) 
			{
				if ((*child)->type == "label")
				{
					details.m_label = (*child)->content;
				}
				else if ((*child)->type == "global_ref")
				{
					details.m_globalRef = (*child)->content;
				}
				else if ((*child)->type == "text")
				{
					details.m_text = (*child)->content;
				}
			}

			param.SetGoalDisplayDetails(details.m_label, details.m_globalRef, details.m_text);
			break;
		}
	}
	else if ( node->type == "correct_decisions")
	{
		param.AddCorrectDecisionsInfo();

		atc::InfoDisplayDetails details;

		for (xml::DocNodes::const_iterator child = node->children.begin();
				child != node->children.end(); 
				++child) 
		{
			if ((*child)->type == "label")
			{
				details.m_label = (*child)->content;
			}
			else if ((*child)->type == "global_ref")
			{
				details.m_globalRef = (*child)->content;
			}
			else if ((*child)->type == "text")
			{
				details.m_text = (*child)->content;
			}
		}

		param.SetCorrectDecisionsDisplayDetails(details.m_label, 
												details.m_globalRef, 
												details.m_text);
	}
	else if ( node->type == "incorrect_decisions")
	{
		param.AddIncorrectDecisionsInfo();

		atc::InfoDisplayDetails details;

		for (xml::DocNodes::const_iterator child = node->children.begin();
				child != node->children.end(); 
				++child) 
		{
			if ((*child)->type == "label")
			{
				details.m_label = (*child)->content;
			}
			else if ((*child)->type == "global_ref")
			{
				details.m_globalRef = (*child)->content;
			}
			else if ((*child)->type == "text")
			{
				details.m_text = (*child)->content;
			}
		}

		param.SetIncorrectDecisionsDisplayDetails(	details.m_label, 
													details.m_globalRef, 
													details.m_text);
	}
	else if ( "score" == node->type )	
	{
		param.add_score_info();
	}
	else if ( "tool"  == node->type )	
	{
		param.add_tool_info();
	}
	else
	{
		throw nodehandler_error( "illegal param node entry <" + node->type + ">" );
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::AircraftDeclarationNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------
void 
AircraftDeclarationNodeHandler::operator()(const xml::DocumentNode* a_node) 
{
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	if (a_node->type == "text")	
	{
		unsigned int row = 0;
		std::string value = "";

		if (_doc->attributeExists(a_node, "row"))
		{
			row = _doc->getIntegerAttribute(a_node, "row");
		}

		if (_doc->attributeExists(a_node, "value"))
		{
			value = _doc->getAttributeValue(a_node, "value");
		}

		param.SetAircraftDeclarationText(row, value);
	}
	else if (a_node->type == "button")	
	{
		std::string name = "";
		std::string type = "";
		std::string label = "";

		if (_doc->attributeExists(a_node, "name"))
		{
			name = _doc->getAttributeValue(a_node, "name");
		}

		if (_doc->attributeExists(a_node, "type"))
		{
			type = _doc->getAttributeValue(a_node, "type");
		}

		if (_doc->attributeExists(a_node, "label"))
		{
			label = _doc->getAttributeValue(a_node, "label");
		}

		param.SetAircraftDeclarationButton(name, type, label);
	}
	else
	{
		throw nodehandler_error( "illegal param node entry <" + a_node->type + ">" );
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::ToolsNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void ToolsNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

    if ( "scale" == node->type ) {

		param.set_scale_tool( *new atc::ToolParams(
				new atc::ScaleHandlerBuilder( _doc->getBooleanAttribute( node, "fixed" ) )
			) );
		std::string pos = _doc->getAttributeValue( node, "position" );
		param.set_scale_positon(
				"TOPLEFT"     == pos ?		atc::TOPLEFT		:
				"TOP"         == pos ?		atc::TOP    		:
				"TOPRIGHT"    == pos ?		atc::TOPRIGHT		:
				"LEFT"        == pos ?		atc::LEFT			:
				"CENTER"      == pos ?		atc::CENTER  		:
				"RIGHT"       == pos ?		atc::RIGHT			:
				"BOTTOMLEFT"  == pos ?		atc::BOTTOMLEFT		:
				"BOTTOMRIGHT" == pos ?		atc::BOTTOMRIGHT	:
											atc::BOTTOM		
			);
	}
	else if ( "altitude" == node->type ) {
        AltitudeNodeHandler tmp(_doc, _view);
        _doc->process_children(node, tmp);
	}
	else if ( "airspeed" == node->type ) 
			param.set_airspeed_tool( *new atc::ToolParams(new atc::VelocityHandlerBuilder()) );
	else
			throw nodehandler_error( "illegal param node entry <" + node->type + ">" );
}

void 
AltitudeNodeHandler::operator()(const xml::DocumentNode* node) 
{
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	atc::AltitudeHandlerBuilder *ahb = new atc::AltitudeHandlerBuilder();

	if (node->type == "aircraftDeclaration")
	{
        AircraftDeclarationNodeHandler tmp(_doc, _view);
        _doc->process_children(node, tmp);
		ahb->SetAircraftDeclaration(param.GetAircraftDeclaration());
	}

	if ( _doc->attributeExists(node, "x") && _doc->attributeExists(node, "y") ){
		ahb->setXY( 
				_doc->getIntegerAttribute(node, "x"),
				_doc->getIntegerAttribute(node, "y") 
			);
	}
	
	param.set_altitude_tool( *new atc::ToolParams(ahb) );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::KeysNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void KeysNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	using namespace atc;
	CanvasItem::TOOL tool 
			= "history_tool"	== node->type	?	CanvasItem::HISTORY_TOOL
			: "srprobe_tool"	== node->type	?	CanvasItem::SRPROBE_TOOL
			: "route_tool"		== node->type	?	CanvasItem::ROUTE_TOOL
			: "vector_tool"		== node->type	?	CanvasItem::VECTOR_TOOL
			: "brline_tool"		== node->type	?	CanvasItem::BRLINE_TOOL
			: "accept_tool"		== node->type	?	CanvasItem::ACCEPT_TOOL
			: "handoff_tool"	== node->type	?	CanvasItem::HANDOFF_TOOL
			: "pause_tool"		== node->type	?	CanvasItem::PAUSE_TOOL
			: "resume_tool"		== node->type	?	CanvasItem::RESUME_TOOL
			:										CanvasItem::NO_TOOL
			;

	std::string key = _doc->getAttributeValue( node, "key" ); 
	std::string tag = _doc->getAttributeValue( node, "tag" );

	if ( 1 != key.length() )
			throw nodehandler_error( "illegal tool key value <" + node->type + ">" );

	param.set_keyed_tool( key[0], tool, tag );
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::InitialToolsNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 */
void InitialToolsNodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>( _view );
	atc::Param& param = task->engine()->param();

	if ( "srprobe_tool" == node->type ) {
		param.set_srprobe( _doc->getIntegerAttribute( node, "toggle" ) );
	}
	else {
		throw nodehandler_error( "illegal tool initialization <" + node->type + ">" );
	}

//	param.set_keyed_tool( key[0], tool, tag );
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// pact::ScoringNodeHandler : xml::NodeHandler
//--------------------------------------------------------------------------------------------------

/*!
 * Constructor
 */
ScoringNodeHandler::ScoringNodeHandler(
	const xml::Document* doc, 
	xml::DocumentView* view
)
	:xml::NodeHandler(doc, view)
	,_builder()
{}


/*!
 * Destructor
 */
ScoringNodeHandler::~ScoringNodeHandler() {}


//--------------------------------------------------------------------------------------------------
// [public] xml::NodeHandler interface
//

void
ScoringNodeHandler::operator()( const xml::DocumentNode *node ) 
{
//  TrialTask* task = dynamic_cast<TrialTask*>( _view );
//	atc::Param& param = task->engine()->param();

	if ("initial" == node->type) 
	{
		set_score(node, &atc::ScoreBuilder::set_score);
	}
	else if (node->type == "correct_decision_links")
	{
		std::list<std::string> link_list;

		for (xml::DocNodes::const_iterator child = node->children.begin();
				child != node->children.end(); 
				++child) 
		{
			link_list.push_back((*child)->content);
		}

		std::string correctDecisionLink;

		if (_doc->attributeExists(node, "idxref"))
		{
			correctDecisionLink = _doc->getAttributeValue(node, "idxref");
		}

		_builder.SetCorrectDecisionLinks(link_list, correctDecisionLink);

	}
	else if (node->type == "incorrect_decision_links")
	{
		std::list<std::string> link_list;

		for (xml::DocNodes::const_iterator child = node->children.begin();
				child != node->children.end(); 
				++child) 
		{
			link_list.push_back((*child)->content);
		}

		std::string incorrectDecisionLink;

		if (_doc->attributeExists(node, "idxref"))
		{
			incorrectDecisionLink = _doc->getAttributeValue(node, "idxref");
		}

		_builder.SetIncorrectDecisionLinks(link_list, incorrectDecisionLink);
	}
	else if (node->type == "goal_success_score_multiplier")
	{
		_builder.SetGoalSuccessScoreMultiplier(atoi(_doc->getStringContent(node).c_str()));
	}
	else if (node->type == "goal_failure_score")
	{
		_builder.SetGoalFailureScore(atoi(_doc->getStringContent(node).c_str()));
	}
	else if (node->type == "goal_success")
	{
		std::string ref1;
		if (_doc->attributeExists(node, "idxref1"))
		{
			ref1 = _doc->getAttributeValue(node, "idxref1");
		}

		std::string ref2;
		if (_doc->attributeExists(node, "idxref2"))
		{
			ref2 = _doc->getAttributeValue(node, "idxref2");
		}

		std::string comp;
		if (_doc->attributeExists(node, "comparison"))
		{
			comp = _doc->getAttributeValue(node, "comparison");
		}

		_builder.SetGoalSuccessFormula(ref1, ref2, comp);
	}
	else if (node->type == "goal_failure")
	{
		std::string ref1;
		if (_doc->attributeExists(node, "idxref1"))
		{
			ref1 = _doc->getAttributeValue(node, "idxref1");
		}

		std::string ref2;
		if (_doc->attributeExists(node, "idxref2"))
		{
			ref2 = _doc->getAttributeValue(node, "idxref2");
		}

		std::string comp;
		if (_doc->attributeExists(node, "comparison"))
		{
			comp = _doc->getAttributeValue(node, "comparison");
		}

		_builder.SetGoalFailFormula(ref1, ref2, comp);
	}
	else if ("already_actioned" == node->type)
	{
		set_score(		node, &atc::ScoreBuilder::SetAlreadyActionedScore);
		set_audio(		node, &atc::ScoreBuilder::SetAlreadyActionedAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetAlreadyActionedDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("hit_conflict_ontime" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetHitConflictOnTimeScore);
		set_audio(		node, &atc::ScoreBuilder::SetHitConflictOnTimeAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetHitConflictOnTimeDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("hit_conflict_not_ontime" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetHitConflictNotOnTimeScore);
		set_audio(		node, &atc::ScoreBuilder::SetHitConflictNotOnTimeAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetHitConflictNotOnTimeDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("hit_after_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetHitAfterConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetHitAfterConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetHitAfterConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("too_late_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetTooLateConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetTooLateConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetTooLateConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("false_alarm_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetFalseAlarmConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetFalseAlarmConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetFalseAlarmConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("false_alarm_conflict_non_target" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetFalseAlarmConflictNonTargetScore);
		set_audio(		node, &atc::ScoreBuilder::SetFalseAlarmConflictNonTargetAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetFalseAlarmConflictNonTargetDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("hit_non_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetHitNonConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetHitNonConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetHitNonConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("too_late_non_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetTooLateNonConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetTooLateNonConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetTooLateNonConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("false_alarm_non_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("false_alarm_non_conflict_non_target" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictNonTargetScore);
		set_audio(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictNonTargetAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetFalseAlarmNonConflictNonTargetDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
    else if ("prior_conflict_for_conflict_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorConflictForConflictPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorConflictForConflictPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorConflictForConflictPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("prior_conflict_for_non_conflict_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorConflictForNonConflictPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorConflictForNonConflictPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorConflictForNonConflictPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("prior_conflict_for_non_target_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorConflictForNonTargetPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorConflictForNonTargetPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorConflictForNonTargetPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("prior_non_conflict_for_conflict_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorNonConflictForConflictPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorNonConflictForConflictPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorNonConflictForConflictPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("prior_non_conflict_for_non_conflict_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonConflictPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonConflictPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonConflictPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("prior_non_conflict_for_non_target_pair" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonTargetPairScore);
		set_audio(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonTargetPairAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetPriorNonConflictForNonTargetPairDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
    else if ("miss_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetMissConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetMissConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetMissConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
    else if ("miss_non_conflict" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::SetMissNonConflictScore);
		set_audio(		node, &atc::ScoreBuilder::SetMissNonConflictAudio);
		SetDelay(		node, &atc::ScoreBuilder::SetMissNonConflictDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else if ("missed_acceptance" == node->type) 
	{
		set_score(		node, &atc::ScoreBuilder::set_missed_acceptance_score);
		set_audio(		node, &atc::ScoreBuilder::set_missed_acceptance_audio);
		SetDelay(		node, &atc::ScoreBuilder::SetMissedAcceptanceDelay);
		SetReference(	node, node->type, &atc::ScoreBuilder::SetReference);
	}
	else 
	{
		throw nodehandler_error("illegal tool initialization <" + node->type + ">");
	}
}

/*!
 *
 */
void ScoringNodeHandler::done() {
	TrialTask* task = dynamic_cast< TrialTask* > ( _view );
	atc::Param& param = task->engine()->param();

	param.add_scoring( _builder.build() );
}


//--------------------------------------------------------------------------------------------------
// [private] 

/*!
 *
 */
void 
ScoringNodeHandler::set_score(	const xml::DocumentNode *node, 
								atc::ScoreBuilder* (atc::ScoreBuilder::*score)(int)) 
{
	if (_doc->attributeExists(node, "value"))
	{
		(_builder.*score)(_doc->getIntegerAttribute(node, "value"));
	}
}

/*!
 *
 */
void ScoringNodeHandler::set_audio(
		const xml::DocumentNode *node,
		atc::ScoreBuilder* (atc::ScoreBuilder::*audio)(const std::string&, int)
) {
	if ( _doc->attributeExists( node, "audio" ) && _doc->attributeExists( node, "duration" ) )
			(_builder.*audio)( 
					_doc->getAttributeValue( node, "audio" ),
					_doc->getIntegerAttribute( node, "duration" )
				);
}

void
ScoringNodeHandler::SetDelay(	const xml::DocumentNode* node,
								atc::ScoreBuilder* (atc::ScoreBuilder::*delay)(int))
{
	if (_doc->attributeExists(node, "delay"))
	{
		(_builder.*delay)(_doc->getIntegerAttribute(node, "delay"));
	}
}

void
ScoringNodeHandler::SetReference(	const xml::DocumentNode* a_node,
									std::string a_event,
									atc::ScoreBuilder* (atc::ScoreBuilder::*ref)(const std::string&, const std::string&))
{
	if (_doc->attributeExists(a_node, "idxref"))
	{
		(_builder.*ref)(a_event, _doc->getAttributeValue(a_node, "idxref"));
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Trial Task Node Handler
//

/*!
 */
void TrialNodeHandler::operator ()( const xml::DocumentNode* node ) {
	TrialTask* task = dynamic_cast<TrialTask*>(_view);

	if ( "keyEvent" == node->type ) {
		task->addTerminationKey( node->content.c_str() );
	}
	else if ( "timeEvent" == node->type ) {
		task->addTerminationTime( _doc->getIntegerContent( node ) );
	} 
	else {
		throw nodehandler_error(
			"illegal instruction node entry <" + node->type + ">"
		);
	}
}

//==============================================================================
//
// Map
//
//------------------------------------------------------------------------------
// Map Node Handler
//

/*!
 *
 */
void MapNodeHandler::operator ()( const xml::DocumentNode* node ) {
	TrialTask* task = dynamic_cast< TrialTask* >( _view );
	atc::Map& map = task->engine()->map();

	if ( "region" == node->type ) {
		int x = atoi( _doc->getAttributeValue( node, "x"     ).c_str() );
		int y = atoi( _doc->getAttributeValue( node, "y"     ).c_str() );
		int w = atoi( _doc->getAttributeValue( node, "x_dim" ).c_str() );
		int h = atoi( _doc->getAttributeValue( node, "y_dim" ).c_str() );

		map.set_region( x, x + w, y, y + h );
	}

	else if("location" == node->type){
		std::string uid = _doc->getAttributeValue( node, "idx" );
		map.add_location(
				_doc->getAttributeValue( node, "idx" ).c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
			  , "true" == _doc->getAttributeValue( node, "visible" )
		);
	}

	else if ( "location_alias" == node->type ) {
		const xml::DocumentNode* alias = _doc->getReferencedNode( 
				_doc->getAttributeValue( node, "location" )
			);
		map.add_location(
				_doc->getAttributeValue( node, "idx" ).c_str()
			  , atof( _doc->getAttributeValue( alias, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( alias, "y" ).c_str() )
			  , false
		);
	}

	else if("route" == node->type){
        MapRouteNodeHandler tmp(_doc, _view, node);
        _doc->process_children(node, tmp);
	}
	
	else if("sector" == node->type){
        MapSectorNodeHandler tmp(_doc, _view, node);
        _doc->process_children(node, tmp);

	}else{
		throw nodehandler_error(
			"illegal map node entry <" + node->type + ">"
		);
	}
}

//------------------------------------------------------------------------------
// Map Route Node Handler
//

/*!
 * Constructor
 */
MapRouteNodeHandler::MapRouteNodeHandler(
	const xml::Document* doc, 
	xml::DocumentView* view,
	const xml::DocumentNode* node
)
	:xml::NodeHandler(doc, view)
	,_routeID("")
{
	_routeID = _doc->getAttributeValue(node, "idx");

	TrialTask* task = dynamic_cast<TrialTask*>(_view);
	task->engine()->map().create_route(_routeID.c_str());
}

/*!
 * Destructor
 */
MapRouteNodeHandler::~MapRouteNodeHandler()
{}

/*!
 * Decode a map route
 */
void MapRouteNodeHandler::operator()(const xml::DocumentNode* node)
{
	TrialTask* task = dynamic_cast<TrialTask*>(_view);

	const xml::DocumentNode* point = 0;

	if("point" == node->type){
		point =  node;

	}else if("pointref" == node->type){
		point = _doc->getReferencedNode(
			_doc->getAttributeValue(node, "location")
		);

	}else{
		throw nodehandler_error(
			"illegal map route node entry <" + node->type + ">"
		);
	}

	task->engine()->map().add_route_point(
			_routeID.c_str()
		  , atof( _doc->getAttributeValue( point, "x" ).c_str() )
		  , atof( _doc->getAttributeValue( point, "y" ).c_str() )
	);
}

//------------------------------------------------------------------------------
// Map Sector Node Handler
//

/*!
 * Constructor
 */
MapSectorNodeHandler::MapSectorNodeHandler(
	const xml::Document* doc, 
	xml::DocumentView* view,
	const xml::DocumentNode* node
)
	:xml::NodeHandler(doc, view)
	,_sectorID("")
{
	_sectorID = _doc->getAttributeValue(node, "idx");
	
	bool is_active = "active" == _doc->getAttributeValue( node, "status" );

	TrialTask* task = dynamic_cast<TrialTask*>(_view);
	atc::Map& map = task->engine()->map();
	map.create_sector( _sectorID.c_str() );
	
	if ( is_active ) {
		map.set_sector_active( _sectorID.c_str() );
	}
}


/*!
 * Destructor
 */
MapSectorNodeHandler::~MapSectorNodeHandler() {}


/*!
 * Decode a map sector
 */
void MapSectorNodeHandler::operator()(
		const xml::DocumentNode* node
){
	TrialTask* task = dynamic_cast< TrialTask* >( _view );
	atc::Map& map = task->engine()->map();

	if ( "arc" == node->type ) {
		map.add_sector_arc(
				_sectorID.c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "r" ).c_str() )
		);
	}
	else if ( "vertex" == node->type ) {
		map.add_sector_vertex(
				_sectorID.c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
		);
	}
	else if ( "ellipse" == node->type ) {
		// @todo:
		throw nodehandler_error( "sector ellipse *NOT* implemented!" );
	}
	else if ( "remove" == node->type ) {
		// @todo: 
		throw nodehandler_error( "remove sector area *NOT* implemented!" );
	}
	else{
		throw nodehandler_error(
			"illegal map sector node entry <" + node->type + ">"
		);
	}
}

//==============================================================================
//
// Sky
//
//------------------------------------------------------------------------------
// Sky Node Handler
//

/*!
 */
void SkyNodeHandler::operator()( const xml::DocumentNode* node ) 
{
	TrialTask* task = dynamic_cast< TrialTask* > ( _view );

	if ( "aircraft" == node->type ) {
		task->engine()->sky().create_aircraft(
				_doc->getAttributeValue(node, "idx" ).c_str()
			  , _doc->getAttributeValue(node, "type").c_str()
		);
        SkyAircraftNodeHandler tmp( _doc, _view );
        _doc->process_children(node, tmp);
	}
	else if ( "area" == node->type ) {
        AreaNodeHandler tmp( _doc, _view, node );
        _doc->process_children(node, tmp);
	}
    else if ( "aircraftstatus" == node->type ) {
        AircraftStatusNodeHandler tmp(_doc, _view, node);
        _doc->process_children( node, tmp);
	}
	else{
		throw nodehandler_error(
				"illegal sky node entry <" + node->type + ">"
		);
	}
}

//------------------------------------------------------------------------------
// Sky Aircraft Node Handler
//

/*!
 * Decode a sky Aircraft
 */
void SkyAircraftNodeHandler::operator()(const xml::DocumentNode* node)
{
	TrialTask* task = dynamic_cast<TrialTask*>(_view);
	atc::Sky& sky = task->engine()->sky();

	std::string planeID(_doc->getAttributeValue(node->parent, "idx"));

	if ( "start" == node->type ) {
		sky.set_aircraft_launch(
				planeID.c_str(),
				_doc->getIntegerContent(node)
			);

	}else if("altitude" == node->type){
		sky.set_aircraft_initialaltitude(
			planeID.c_str(),
			_doc->getDecimalContent(node)
		);

	}else if("velocity" == node->type){
		sky.set_aircraft_initialvelocity(
			planeID.c_str(),
			_doc->getDecimalContent(node)
		);

	}else if("flightpath" == node->type){
        SkyAircraftFlightpathNodeHandler tmp(_doc, _view);
        _doc->process_children(node, tmp);

	}else if("closedpath" == node->type){
		sky.set_aircraft_closedpath(planeID.c_str(), true);

	}else{
		throw nodehandler_error(
			"illegal sky aircraft node entry <" + node->type + ">"
		);
	}
}

//------------------------------------------------------------------------------
// Sky Aircraft FlightPath Node Handler
//

/*!
 * Decode a sky aircraft's flight path
 */
void SkyAircraftFlightpathNodeHandler::operator()(
	const xml::DocumentNode* node
){
	TrialTask* task = dynamic_cast<TrialTask*>(_view);

	if ( "point" == node->type ) {
		task->engine()->sky().add_aircraft_pathdescriptor(
				_doc->getAttributeValue(node->parent->parent, "idx").c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
			  , _doc->exists(node, "altitude")
					? _doc->getDecimalContent(node, "altitude")	: atc::NAN
			  , _doc->exists(node, "ascent")
					? _doc->getDecimalContent(node, "ascent") : atc::NAN
			  , _doc->exists(node, "velocity")
					? _doc->getDecimalContent(node, "velocity") : atc::NAN
			  , _doc->exists(node, "acceleration")
					? _doc->getDecimalContent(node, "acceleration") : atc::NAN
		);
	}

	else if ( "pointref" == node->type ) {
		const xml::DocumentNode *alias = _doc->getReferencedNode(
				_doc->getAttributeValue( node, "location" )
			);
		if ( "location_alias" == alias->type ) {
			alias = _doc->getReferencedNode(
					_doc->getAttributeValue( alias, "location" )
				);
		}

		task->engine()->sky().add_aircraft_pathdescriptor(
				_doc->getAttributeValue(node->parent->parent, "idx").c_str()
			  , atof( _doc->getAttributeValue( alias, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( alias, "y" ).c_str() )
			  , _doc->exists(node, "altitude")
					? _doc->getDecimalContent(node, "altitude")	: atc::NAN
			  , _doc->exists(node, "ascent")
					? _doc->getDecimalContent(node, "ascent") : atc::NAN
			  , _doc->exists(node, "velocity")
					? _doc->getDecimalContent(node, "velocity") : atc::NAN
			  , _doc->exists(node, "acceleration")
					? _doc->getDecimalContent(node, "acceleration") : atc::NAN
		);
	}
	
	else {
		throw nodehandler_error(
				"illegal sky aircraft flightpath entry <" + node->type + ">"
			);
	}
}

//------------------------------------------------------------------------------
// Sky "area" node handler.
//

/*!
 * Constructor
 */
AreaNodeHandler::AreaNodeHandler(
	const xml::Document* doc, 
	xml::DocumentView* view,
	const xml::DocumentNode* node
)
	:xml::NodeHandler(doc, view)
	,_areaID( _doc->getAttributeValue( node, "idx" ) )
{
	TrialTask* task = dynamic_cast< TrialTask* >( _view );
	atc::Sky& sky = task->engine()->sky();
	sky.create_weather( _areaID.c_str() );
}


/*!
 * Destructor
 */
AreaNodeHandler::~AreaNodeHandler() {}


/*!
 *
 */
void AreaNodeHandler::operator()( const xml::DocumentNode* node ) {
	TrialTask* task = dynamic_cast< TrialTask* > ( _view );
	atc::Sky& sky = task->engine()->sky();

	if ( "arc" == node->type ) {
		sky.add_weather_arc(
				_areaID.c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "r" ).c_str() )
		);
	}
	else if ( "vertex" == node->type ) {
		sky.add_weather_vertex(
				_areaID.c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
		);
	}
	else if ( "ellipse" == node->type ) {
		sky.add_weather_ellipse(
				_areaID.c_str()
			  , atof( _doc->getAttributeValue( node, "x" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "y" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "w" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "h" ).c_str() )
			  , atof( _doc->getAttributeValue( node, "a" ).c_str() )
		);
	}
	else if ( "remove" == node->type ) {
		// @todo:
		throw nodehandler_error( "'remove' area *NOT* implemented!" );
	}
	else{
		throw nodehandler_error(
			"illegal map sector node entry <" + node->type + ">"
		);
	}
}


//------------------------------------------------------------------------------
// Sky "aircraftstatus" node handler.
//
AircraftStatusNodeHandler::AircraftStatusNodeHandler(
    const xml::Document* a_doc,
    xml::DocumentView* a_view,
    const xml::DocumentNode* )
: xml::NodeHandler(a_doc, a_view), m_builder()
{
	//m_builder.set_separation( _doc->getDoubleAttribute( node, "separation" ) );
}

AircraftStatusNodeHandler::~AircraftStatusNodeHandler() 
{
}

void 
AircraftStatusNodeHandler::operator()(const xml::DocumentNode* a_node) 
{
	if ("aircraft" == a_node->type)
	{
		m_builder.add_aircraft(_doc->getStringContent(a_node));
	}
	else if (a_node->type == "status")
	{
		std::string status = _doc->getStringContent(a_node);
		atc::ConflictDeclaration::ConflictType conflictType = atc::ConflictDeclaration::CONFLICT_TYPE_NON_CONFLICT;

		if (status == "conflict")
		{
			conflictType = atc::ConflictDeclaration::CONFLICT_TYPE_CONFLICT;
		}

		m_builder.SetConflictType(conflictType);
	}
	else if (a_node->type == "finaltime")
	{
		m_builder.SetFinalTime(_doc->getIntegerContent(a_node)); 
	}
	else
	{
		throw nodehandler_error("illegal sky aircraftstatus node entry <" + a_node->type + ">");
	}
}

void 
AircraftStatusNodeHandler::done() 
{
	TrialTask* task = dynamic_cast< TrialTask* > (_view);
	atc::Sky& sky = task->engine()->sky();

	sky.add_conflicts(m_builder.build());
}

//==============================================================================
//
// User Interface
//
//------------------------------------------------------------------------------
// UI Node Handler
//

void UINodeHandler::build_dialog( 
		const xml::DocumentNode *node, 
		TrialTask *task 
) {
	Dialog *d = new Dialog( 
			task, 
			_doc->getAttributeValue(node, "idx").c_str() 
		);

	for(
		xml::ChildCIt child = node->children.begin();
		child != node->children.end();
		++child
	){
			if ( "font" == (*child)->type ) {
				d->setFont( QFont( 
						_doc->getAttributeValue( *child, "family" ).c_str(),
						_doc->getIntegerAttribute( *child, "pointSize" ),
						_doc->getIntegerAttribute( *child, "weight" ),
						_doc->getBooleanAttribute( *child, "italic" )
					) );
			}

			else if ( "caption" == (*child)->type ) {
				d->setCaption( _doc->getStringContent( *child ).c_str() );
			}

			else if ( "ui_component" == (*child)->type ) {
				d->addWidget( UIComponentBuilder::build(
						_doc,
						_doc->getReferencedNode( 
								_doc->getAttributeValue(*child, "ref") 
							),
						d
					) );
			}

			else if ( "connection" == (*child)->type ) {
                UIConnectionNodeHandler tmp( _doc, task );
                _doc->process_children((*child), tmp);
			}

			else if ( "timer" == (*child)->type ) {
				int interval = _doc->getIntegerAttribute( *child, "interval" );
				d->setInterval( interval );

				if ( 
						_doc->attributeExists( *child, "singleShot" ) &&
						_doc->getBooleanAttribute( *child, "singleShot" )
				) {
					d->setSingleShot();
				}
				d->reset_timer();
			}

			else if ( "pause" == (*child)->type ) {
				if ( _doc->getBooleanAttribute( *child, "onShow" ) ) {
					QObject::connect( d, SIGNAL( shown() ), task, SLOT( pause() ) );
					QObject::connect( d, SIGNAL( hidden() ), task, SLOT( resume() ) );
				}
			}

			else if ( "locate" == (*child)->type ) {
				d->setLocation( _doc->getAttributeValue( *child, "grid" ) );
			}
	}

}

/*!
 */
void UINodeHandler::operator()( const xml::DocumentNode *node ) {
	TrialTask* task = dynamic_cast<TrialTask*>(_view);

	if ( "dialog" == node->type ) {
		build_dialog( node, task );
	}

	else {
		throw nodehandler_error(
			"illegal user interface entry <" + node->type + ">"
		);
	}
}


//------------------------------------------------------------------------------
// UI Connection Node Handler
//

/*!
 * Decode User Interface Connections
 */
void UIConnectionNodeHandler::operator()( const xml::DocumentNode *node ) {

	Task* task = dynamic_cast< Task * >( _view );

	if("signal" == node->type){
		_tx = 
			_doc->attributeExists(node, "tx")
			? widget_ptr(_doc->getAttributeValue(node, "tx"))
			: task;
		_sig = node->content;

	}else if("slot" == node->type){
		_rx = 
			_doc->attributeExists(node, "rx")
			? widget_ptr(_doc->getAttributeValue(node, "rx"))
			: task;
		_slot = node->content;

		connect();

	}else{
		throw nodehandler_error(
			"illegal user interface connection entry <" + node->type + ">"
		);
	}
}

/*!
 * Look up a widget using it's name and return a pointer to it.
 *
 * @param name widget's name
 * @return a pointer to the named widget (or NULL)
 */
QWidget* UIConnectionNodeHandler::widget_ptr(
	const std::string& name
)const{

	foreach(QWidget* w, QApplication::allWidgets()) {
		if ( name == w->name() ) return w;
	}

    return NULL;
}

/*!
 */
void UIConnectionNodeHandler::connect()const
{
    Q_ASSERT( _tx && _sig.size() );
    Q_ASSERT( _rx && _slot.size() );

	QObject::connect(
		_tx, QString( "2%1" ).arg( QString(_sig.c_str()).stripWhiteSpace() ),
		_rx, QString( "1%1" ).arg( QString(_slot.c_str()).stripWhiteSpace() ) 
	);

}
